package cn.edu.ptu.jobfairs.services.impl;

import cn.edu.ptu.jobfairs.basic.bo.Member;
import cn.edu.ptu.jobfairs.basic.bo.MemberPos;
import cn.edu.ptu.jobfairs.basic.bo.Position;
import cn.edu.ptu.jobfairs.basic.common.DataResult;
import cn.edu.ptu.jobfairs.basic.common.Result;
import cn.edu.ptu.jobfairs.basic.dto.BaseInfoDTO;
import cn.edu.ptu.jobfairs.basic.dto.request.IdDTO;
import cn.edu.ptu.jobfairs.basic.dto.request.PwChangeDTO;
import cn.edu.ptu.jobfairs.basic.dto.UserAuthDTO;
import cn.edu.ptu.jobfairs.basic.enums.MemberStatus;
import cn.edu.ptu.jobfairs.core.SqlHandler;
import cn.edu.ptu.jobfairs.core.config.Consts;
import cn.edu.ptu.jobfairs.core.security.MD5PasswordEncoder;
import cn.edu.ptu.jobfairs.core.utils.SqlBuilder;
import cn.edu.ptu.jobfairs.core.utils.UserUtils;
import cn.edu.ptu.jobfairs.core.utils.ValidUtils;
import cn.edu.ptu.jobfairs.services.UserService;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static cn.edu.ptu.jobfairs.basic.common.Errors.*;

/**
 * Created by Lin Chenxiao on 2020-08-23
 **/
@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Resource
    private SqlHandler sqlHandler;
    @Resource
    private MD5PasswordEncoder md5PasswordEncoder;

    @Override
    @PostAuthorize("hasAuthority('admin')")
    public Result addUsers(Member member) {
        if (ValidUtils.hasBlank(member, "id", "pwMd5", "status", "createTime", "updateTime")) return Result.fail(INVALID_PARAMS);
        sqlHandler.notExists(SqlBuilder.from("select count(*) from # where # limit 1")
                .append(Member.class).whereCrc("number", member.getNumber()));
        long time = System.currentTimeMillis();
        member.setPwMd5(md5PasswordEncoder.encode(Consts.USER_PASSWORD));
        member.setStatus(MemberStatus.USER.getValue());
        member.setCreateTime(time);
        member.setUpdateTime(time);
        Integer id = sqlHandler.create(SqlBuilder.from("insert into # #").append(Member.class).insert(member));
        return DataResult.ok(id);
    }

    @Override
    @PostAuthorize("hasAuthority('admin')")
    public Result editUsers(Member member) {
        if (member == null || member.getId() == null) return Result.fail(INVALID_PARAMS);
        if (!StringUtils.isEmpty(member.getNumber())) {
            sqlHandler.notExists(SqlBuilder.from("select count(*) from # where # and id != # limit 1")
                    .append(Member.class).whereCrc("number", member.getNumber()).append(member.getId()));
        }
        member.setCreateTime(null);
        member.setUpdateTime(System.currentTimeMillis());
        sqlHandler.updateOne(SqlBuilder.from("update # set # where # limit 1")
                .append(Member.class).update(member).where(member.getId()));
        return Result.OK;
    }

    @Override
    @PostAuthorize("hasAuthority('admin')")
    public Result resetPassword(IdDTO idDTO) {
        if (idDTO == null || idDTO.getId() == null) return Result.fail(INVALID_PARAMS);
        Member member = new Member();
        member.setId(idDTO.getId());
        member.setPwMd5(md5PasswordEncoder.encode(Consts.USER_PASSWORD));
        member.setUpdateTime(System.currentTimeMillis());
        sqlHandler.updateOne(SqlBuilder.from("update # set # where # limit 1")
                .append(Member.class).update(member).where(member.getId()));
        return DataResult.ok(Consts.USER_PASSWORD);
    }

    @Override
    public Result changePassword(PwChangeDTO pwChangeDTO) {
        if (ValidUtils.hasBlank(pwChangeDTO)) return Result.fail(INVALID_PARAMS);
        Integer id = UserUtils.getId();
        Member member = new Member();
        member.setPwMd5(pwChangeDTO.getNewPw());
        member.setUpdateTime(System.currentTimeMillis());
        return sqlHandler.update(SqlBuilder.from("update # set # where # and # limit 1")
                .append(Member.class).update(member).where(id).where("pwMd5", pwChangeDTO.getOldPw())) > 0 ?
                Result.OK : Result.fail(INVALID_PASSWORD);
    }

    @Override
    @PostAuthorize("hasAuthority('admin')")
    public Result authUser(UserAuthDTO userAuthDTO) {
        if (ValidUtils.hasBlank(userAuthDTO, "positions")) return Result.fail(INVALID_PARAMS);
        if (!MemberStatus.exists(userAuthDTO.getStatus()))return Result.fail(INVALID_PARAMS);
        Member member = new Member();
        member.setStatus(userAuthDTO.getStatus());
        member.setUpdateTime(System.currentTimeMillis());
        sqlHandler.updateOne(SqlBuilder.from("update # set # where # limit 1")
                .append(Member.class).update(member).where(userAuthDTO.getId()));
        if (userAuthDTO.getStatus() == MemberStatus.USER.getValue()) {
            sqlHandler.delete(SqlBuilder.from("delete from # where #").append(MemberPos.class)
                    .where("memberId", userAuthDTO.getId()));
            if (!CollectionUtils.isEmpty(userAuthDTO.getPositions())) {
                List<MemberPos> list = new LinkedList<>();
                for (Integer i : userAuthDTO.getPositions()) {
                    MemberPos memberPos = new MemberPos();
                    memberPos.setMemberId(userAuthDTO.getId());
                    memberPos.setPositionId(i);
                    list.add(memberPos);
                }
                sqlHandler.insert(SqlBuilder.from("insert into # #").append(MemberPos.class).insert(list));
            }
        }
        return Result.OK;
    }

    @Override
    @PostAuthorize("hasAuthority('admin')")
    public Result getAuth(IdDTO idDTO) {
        if (idDTO == null || idDTO.getId() == null) return Result.fail(INVALID_PARAMS);
        Member member = sqlHandler.select(SqlBuilder.from("select status from # where #")
                .append(Member.class).where(idDTO.getId()), Member.class);
        if (member == null) return Result.fail(RECORD_NOT_EXISTS);
        UserAuthDTO userAuthDTO = new UserAuthDTO();
        userAuthDTO.setStatus(member.getStatus());
        if (member.getStatus() == MemberStatus.USER.getValue()) {
            List<MemberPos> list = sqlHandler.selectAll(SqlBuilder.from("select position_id from # where #")
                    .append(MemberPos.class).where("memberId", idDTO.getId()), MemberPos.class);
            if (!CollectionUtils.isEmpty(list))
                userAuthDTO.setPositions(list.stream().map(MemberPos::getPositionId).collect(Collectors.toList()));
        }
        return DataResult.ok(userAuthDTO);
    }

    @Override
    public Result listUsers() {
        return DataResult.ok(sqlHandler.selectAll(SqlBuilder.from("select id, number, name, title, phone, status from #")
                .append(Member.class), Member.class));
    }

    @Override
    public Result listBaseInfo() {
        List<Member> members = sqlHandler.selectAll(SqlBuilder.from("select id, name from #")
                .append(Member.class), Member.class);
        List<Position> positions = sqlHandler.selectAll(SqlBuilder.from("select id, name from #")
                .append(Position.class), Position.class);
        return DataResult.ok(new BaseInfoDTO(members, positions));
    }
}
